package seismosurfer.servlets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import seismosurfer.data.SourceData;
import seismosurfer.data.constants.UpdateConstants;
import seismosurfer.domain.Quake;
import seismosurfer.domain.SeismoLatLon;
import seismosurfer.util.TimeUtil;
import seismosurfer.util.UserException;

import com.bbn.openmap.util.Debug;

/**
 * This servlet handles all the operations
 * that are accessed from the homepage. 
 *
 */
public class QuakeController extends BaseServlet {
    
    private static final long serialVersionUID = -8660550271949248721L;

    public static final String LOAD = "load";

    public static final String UNLOAD = "unload";

    public static final String CENTER = "center";

    public static final String SOURCES = "sources";

    public static final String QUAKES = "quakes";

    public static final String INTERVALS = "intervals";

    public static final String UPDATE = "update";

    public QuakeController() {
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try {

            Debug.output(request.getRequestURL().toString());

            String source = request.getParameter(SOURCE);
            String interval = request.getParameter(INTERVAL);

            Quake quake = new Quake();

            if ((source == null) && (interval == null)) {
                // default (first) request
                source = Quake.DEFAULT_SOURCE;
                interval = quake.getDefaultInterval();
            } else if (source == null) {
                // we hold the chosen source in a session attribute
                source = (String) request.getSession().getAttribute(SOURCE);
                if (source == null) {
                    source = Quake.DEFAULT_SOURCE;
                }
            } else if (interval == null) {
                // user chose another datasource
                interval = (String) request.getSession().getAttribute(INTERVAL);
                if (interval == null) {
                    interval = quake.getDefaultInterval();
                }
            }

            Debug.output(source);
            Debug.output(interval);

            List result = quake.getTopEvents(source, interval);
            // transformQuakesInXML(result);
            SeismoLatLon center = getCenterCoords(source);

            List sources = quake.getSources();
            String sourcesInHTML = toComboBox(getSourcesAsMap(sources), source);

            // set session variables
            request.getSession().setAttribute(SOURCE, source);
            request.getSession().setAttribute(INTERVAL, interval);

            request.getSession().setAttribute("top", result);

            // set request variables

            request.setAttribute(LOAD, "load()");
            request.setAttribute(UNLOAD, "GUnload()");

            request.setAttribute(CENTER, center);

            request.setAttribute(SOURCES, sourcesInHTML);
            request.setAttribute(INTERVALS, getIntervalsInHTML(interval));
            request.setAttribute(UPDATE, getLastUpdate(sources, source));

        } catch (UserException ex) {
            setErrors(ex.getNotification(), request);
        }
        forward("/main.jsp", request, response);
    }
    
    /**
     * Given a data source, gets the corresponding
     * coordinates of the center of its area.
     * 
     * @param source the data source name
     * @return a SeismoLatLon that holds the coordinates
     */
    protected SeismoLatLon getCenterCoords(String source) {

        SeismoLatLon p = null;

        if (source.equals(UpdateConstants.GI_NOA_SOURCE_NAME)) {
            p = new SeismoLatLon(SourceData.GINOA_LAT, SourceData.GINOA_LNG, 5);
        } else if (source.equals(UpdateConstants.NEIC_SOURCE_NAME)) {
            p = new SeismoLatLon(SourceData.NEIC_LAT, SourceData.NEIC_LNG, 0);
        }

        return p;
    }
    
    /**
     * Gets the latest database update timepoint from a data source.
     * 
     * @param sources a List of data source names
     * @param sourceName the data source name whose last update
     *        is needed
     * @return the time point of the last update as a String
     */
    protected String getLastUpdate(List sources, String sourceName) {

        for (Iterator iter = sources.iterator(); iter.hasNext();) {
            SourceData item = (SourceData) iter.next();
            if (item.getSource().equals(sourceName)) {
                return TimeUtil.toText(item.getLastUpdate());
            }
        }

        return null;
    }

    /**
     * Deals with the presentation of the time
     * intervals for the top events.
     * 
     * @param interval a time interval
     * @return an HTML formatted text
     */
    protected String getIntervalsInHTML(String interval) {
        String intervals[] = { Quake.DAY, Quake.WEEK, Quake.MONTH, Quake.YEAR };

        StringBuffer result = new StringBuffer();

        for (int i = 0; i < intervals.length; i++) {
            if (intervals[i].equals(interval)) {
                result.append(interval + " | ");
            } else {
                result.append(getLink("main?interval=" + intervals[i],
                        intervals[i])
                        + " | ");
            }
        }

        return result.toString();
    }
    
    /**
     * Converts a List of data sources to a Map
     * of data sources which can be used to present them
     * in a combo box.
     * 
     * @param sources  the List with the data sources
     * @return a Map with the data sources
     */
    protected Map getSourcesAsMap(List sources) {
        Map result = new HashMap(sources.size());

        for (Iterator iter = sources.iterator(); iter.hasNext();) {
            SourceData item = (SourceData) iter.next();
            result.put(item.getSource(), item.getSource());
        }
        return result;
    }

}